package bat.iog.hytool.nio.demo1;


import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;

public class NioReadThread implements Runnable {
    /**
     * 消息缓存区
     */
    private static ByteBuffer readBuf = ByteBuffer.allocate(1024);

    private Selector selector;

    private int count = 0;

    public NioReadThread(Selector selector) {
        this.selector = selector;
    }

    @Override
    public void run() {
        try {
            while (true) {
                selector.select();
                //获取所有接收事件的selection-key实例
                Set<SelectionKey> readKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = readKeys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey key = iterator.next();
                    //处理完成之后要将key删除防止重复处理
                    iterator.remove();
                    //检查时间是否是一个新的已经就绪可以被接受的连接
                    if (key.isAcceptable()) {
                        getConnect(key);
//                        key.interestOps(SelectionKey.OP_WRITE & SelectionKey.OP_READ);
                    }
                    //是否可以读取数据
                    if (key.isReadable()) {
                        getMessage(key);
                    }
                    //检查套接字是否已经准备写数据
                    if (key.isWritable()) {
                        writeMessage(key);
//                        sendMessage(key);
                    }

                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取连接
     *
     * @param key
     * @throws Exception
     */
    private void getConnect(SelectionKey key) {
        try {
            //要操作的message
            ByteBuffer msg = ByteBuffer.wrap("connect success ".getBytes());
            ServerSocketChannel serverSocket = (ServerSocketChannel) key.channel();
            //接收一个客户端连接
            SocketChannel client = serverSocket.accept();
            //设置非阻塞
            client.configureBlocking(false);
            //监听读事件
            System.out.println("读消息线程socket" + client);
            //发送连接成功给客户端
            client.write(msg);
            //这里必须监听写的事件 客户端的建立连接否
            client.register(selector, SelectionKey.OP_WRITE|SelectionKey.OP_READ);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 读取数据
     *
     * @param key
     * @throws IOException
     */
    private void getMessage(SelectionKey key) throws IOException {
        readBuf.clear();
        SocketChannel client = (SocketChannel) key.channel();
        try {
            client.configureBlocking(false);
            int count = client.read(readBuf);
            if (count == -1) {
                client.shutdownOutput();
                client.shutdownInput();
                client.close();
                System.out.println("断开scoket连接");
            }
            byte[] bytes = new byte[count];
            readBuf.flip();
            readBuf.get(bytes);
            String message = new String(bytes, 0, count);
            System.out.println("客户端响应:~~~~~~~~~~~~");
            System.out.println(message);
            key.interestOps(SelectionKey.OP_WRITE);
        } catch (IOException e) {
            key.cancel();
            client.close();
            System.out.println("断开连接");
        }
    }


    /**
     * 发送数据
     *
     * @param key
     * @throws IOException
     */
    private void sendMessage(SelectionKey key) {
        SocketChannel channel = (SocketChannel) key.channel();
        try {
            channel.configureBlocking(false);
            String requestLine = "【服务端】发送消息" + count;
            //写数据
            channel.write(ByteBuffer.wrap(requestLine.getBytes()));
            key.interestOps(SelectionKey.OP_READ);
            count++;
            if (count > 10) {
                channel.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 键盘输入模拟聊天发送消息
     *
     * @param key
     * @throws IOException
     */
    private void writeMessage(SelectionKey key) throws IOException {
        SocketChannel channel = (SocketChannel) key.channel();
        channel.configureBlocking(false);
        //键盘输入
        Scanner scanner = new Scanner(System.in);
        StringBuffer stringBuffer = new StringBuffer();
        while (scanner.hasNextLine()) {
            String message = scanner.nextLine();
            if (message.equals("s")) {
                break;
            } else {
                stringBuffer.append(message).append("\n");
            }
        }
        channel.write(ByteBuffer.wrap(stringBuffer.toString().getBytes()));
        key.interestOps(SelectionKey.OP_READ);
    }
}

